package com.zxmzy.scaffold.cardview

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import kotlin.math.abs

/**
 * @author zhangxiaoming
 * @date 2023/8/22
 * @description
 */
class CardView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet?,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
    //阴影颜色
    private var mShadowColor: Int = Color.BLACK

    // 阴影发散距离 blur
    private var mShadowRadius: Float = 0f

    // x,y轴偏移距离
    private var mDx = 0f
    private var mDy = 0f

    //  圆角半径
    private var mCornerRadius = 0f
    private var mCornerRadiusLT = 0f
    private var mCornerRadiusLB = 0f
    private var mCornerRadiusRT = 0f
    private var mCornerRadiusRB = 0f

    // 边框颜色
    private var mBorderColor = 0

    //边框宽度
    private var mBorderWidth = 0f

    // 控制四边是否显示阴影
    private var mShadowSides = FLAG_SIDES_ALL

    // 全局画笔
    private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 全局Path
    private val mPath = Path()

    // 合成模式
    private val mXfermode: PorterDuffXfermode

    // 视图内容区域的RectF实例
    private var mContentRect: RectF? = null

    // 视图边框的RectF实例
    private var mBorderRect: RectF? = null

    companion object {
        private const val FLAG_SIDES_TOP = 1
        private const val FLAG_SIDES_RIGHT = 2
        private const val FLAG_SIDES_BOTTOM = 4
        private const val FLAG_SIDES_LEFT = 8
        private const val FLAG_SIDES_ALL = 15
        private const val DEBUG = false
    }

    init {
        initAttrs(context, attrs)
        val xPadding = (mShadowRadius + abs(mDx)).toInt()
        val yPadding = (mShadowRadius + abs(mDy)).toInt()
        val pl = if (containsFlag(mShadowSides, FLAG_SIDES_LEFT)) xPadding else 0
        val pt = if (containsFlag(mShadowSides, FLAG_SIDES_TOP)) yPadding else 0
        val pr = if (containsFlag(mShadowSides, FLAG_SIDES_RIGHT)) xPadding else 0
        val pb = if (containsFlag(mShadowSides, FLAG_SIDES_BOTTOM)) yPadding else 0
        setPadding(pl, pt, pr, pb)
        setLayerType(View.LAYER_TYPE_SOFTWARE, null)

        mXfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)

        paintReset(mPaint, Color.WHITE)


    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mContentRect = RectF(
            paddingLeft.toFloat(),
            paddingTop.toFloat(),
            (w - paddingRight).toFloat(),
            (h - paddingBottom).toFloat()
        )
        //以边框宽度的三分之一，微调边框绘制位置，以在边框较宽时得到更好的视觉效果
        val bw = (mBorderWidth / 3f).toInt()
        if (bw > 0) {
            mBorderRect = RectF(
                mContentRect!!.left + bw,
                mContentRect!!.top + bw,
                mContentRect!!.right - bw,
                mContentRect!!.bottom - bw
            )
        }
    }

    override fun dispatchDraw(canvas: Canvas?) {
        canvas ?: return
        //绘制阴影
        //绘制阴影
        drawShadow(canvas)
        //绘制子View
        //绘制子View
        drawChild(canvas)
        //绘制边框
        //绘制边框
        drawBorder(canvas)
    }

    private fun drawShadow(canvas: Canvas) {
        mContentRect?.let {
            canvas.save()
            mPaint.setShadowLayer(mShadowRadius, mDx, mDy, mShadowColor)
            canvas.drawRoundRect(it, mCornerRadius, mCornerRadius, mPaint)
            paintReset(mPaint, 0)
        }
    }

    private fun drawChild(canvas: Canvas) {
        canvas.saveLayer(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), mPaint)
        //先绘制子控件
        super.dispatchDraw(canvas)
        //使用path构建四个圆角
        mContentRect?.let {
            mPath.addRect(it, Path.Direction.CW)
            mPath.addRoundRect(it, mCornerRadius, mCornerRadius, Path.Direction.CW)
            mPath.fillType = Path.FillType.EVEN_ODD
            //使用xfermode在图层上进行合成，处理圆角
            mPaint.xfermode = mXfermode
            canvas.drawPath(mPath, mPaint)
            paintReset(mPaint, 0)
            mPath.reset()
        }
        canvas.restore()
    }

    private fun drawBorder(canvas: Canvas) {
        mBorderRect?.let {
            canvas.save()
            mPaint.apply {
                strokeWidth = mBorderWidth
                style = Paint.Style.STROKE
                color = mBorderColor
            }
            canvas.drawRoundRect(it, mCornerRadius, mCornerRadius, mPaint)
            paintReset(mPaint, 0)
            canvas.restore()
        }
    }

    private fun initAttrs(context: Context, attrs: AttributeSet?) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.CardView)
        mShadowColor = a.getColor(R.styleable.CardView_cardShadowColor, mShadowColor)
        mShadowRadius = a.getDimensionPixelSize(R.styleable.CardView_cardShadowRadius, 0).toFloat()
        mDx = a.getDimensionPixelSize(R.styleable.CardView_cardDx, 0).toFloat()
        mDy = a.getDimensionPixelSize(R.styleable.CardView_cardDy, 0).toFloat()
        mCornerRadius = a.getDimensionPixelSize(R.styleable.CardView_cardCornerRadius, 0).toFloat()
        mCornerRadiusLT =
            a.getDimensionPixelSize(R.styleable.CardView_cardCornerRadiusLT, 0).toFloat()
        mCornerRadiusLB =
            a.getDimensionPixelSize(R.styleable.CardView_cardCornerRadiusLB, 0).toFloat()
        mCornerRadiusRT =
            a.getDimensionPixelSize(R.styleable.CardView_cardCornerRadiusRT, 0).toFloat()
        mCornerRadiusRB =
            a.getDimensionPixelSize(R.styleable.CardView_cardCornerRadiusRB, 0).toFloat()
        mBorderColor = a.getColor(R.styleable.CardView_cardBorderColor, mBorderColor)
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CardView_cardBorderWidth, 0).toFloat()
        mShadowSides = a.getInt(R.styleable.CardView_cardSides, FLAG_SIDES_ALL)
        a.recycle()
    }

    private fun containsFlag(sides: Int, flag: Int): Boolean {
        return sides or flag == sides
    }

    private fun paintReset(paint: Paint, color: Int) {
        //这里默认值使用白色，可处理掉系统渲染抗锯齿时，人眼可观察到像素颜色
        paint.run {
            reset()
            this.color = if (color != 0) color else Color.WHITE
            isAntiAlias = true
            style = Paint.Style.FILL
            strokeWidth = 0f
        }
    }
}